from fastapi.responses import JSONResponse as JSONResponse_
from fastapi import HTTPException as HTTPException_
from typing import Any, Optional, Dict
from starlette.background import BackgroundTask
from utils.json import CustomJSONEncoder as JsonEncoder
import json


class HTTPException(HTTPException_):
    def __init__(
            self,
            http_code: int = 400,
            status_code: int = -1,
            detail: Optional[dict] = None,
            message: Optional[str] = None
    ):
        content = {
            "status_code": status_code,
        }

        if detail is not None:
            content['detail'] = detail

        if message is not None:
            content['message'] = message

        super().__init__(detail=content, status_code=http_code)


class JSONResponse(JSONResponse_):
    def render(self, content: Any) -> bytes:
        return json.dumps(
            content,
            ensure_ascii=False,
            allow_nan=False,
            indent=None,
            separators=(",", ":"),
            cls=JsonEncoder
        ).encode("utf-8")


class BadResponse(JSONResponse_):
    def __init__(
            self,
            http_code: int = 400,
            status_code: int = -1,
            detail: Any = None,
            msg: Optional[str] = None,
            headers: Optional[Dict[str, Any]] = None,
            media_type: Optional[str] = 'application/json',
            background: Optional[BackgroundTask] = None
    ):
        content = {
            "status_code": status_code,
            "detail": {}
        }
        detail_type = type(detail)
        if detail_type == str or detail_type == int:
            content["detail"] = detail
        elif detail_type == list or detail_type == tuple:
            content["detail"] = detail
        elif detail_type == dict:
            content.update(detail)
        elif detail is None:
            content["detail"]["msg"] = str(detail)

        if msg is not None:
            content["detail"]["msg"] = msg

        super().__init__(content=content,
                         status_code=http_code,
                         headers=headers,
                         media_type=media_type,
                         background=background)
